# install.packages("sf")
# install.packages("leaflet")
library(sf)
library(tidyverse)
library(leaflet)

Analyzing Aggravated Burglaries in Davidson County

Part 1: Data Preparation

I have been provided these three datasets for this project:

  1. burglaries_2023.csv: Contains data on the aggravated burglary incidents in Davidson County. This was obtained from https://data.nashville.gov/Police/Metro-Nashville-Police-Department-Incidents/2u6v-ujjs.
# read the csv of burglaries data into the notebook

burglary_incidents <- read_csv('../data/burglaries_2023.csv')

# view the dataset

burglary_incidents
NA

Investigate the ethnicity column some:


# investigate the ethnicity column some

unique(burglary_incidents[["victim_ethnicity"]])
[1] "Non-Hispanic" NA             "Hispanic"     "Unknown"     
  1. census.csv: Census tract level data on population and median income. This was obtained from the US Census American Community Survey.

# read the csv of census data into the notebook

census <- read_csv('../data/census.csv')

# view the dataset

census
NA
  1. DC: A shapefile containing Davidson County census tracts

# read in the shape file data for Davidson county census tracts
# read in the DC file data

dav_cty_census_tracts <- read_sf('../data/DC/DC.shp')
dav_cty_census_tracts
Simple feature collection with 174 features and 12 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -87.0547 ymin: 35.96778 xmax: -86.51559 ymax: 36.4055
Geodetic CRS:  NAD83
burglary_incidents
dav_cty_census_tracts |> 
  ggplot() +
  geom_sf()

dav_cty_census_tracts |> 
  ggplot() +
  geom_sf(aes(fill = ALAND))

Perform a spatial join to determine the census tract in which each burglary occurred. Hint: You may want to make use of the st_as_sf function in order to convert the burglaries data into an sf object.


# performed spatial join 

burglary_incidents

burglary_incidents_mapped <- st_as_sf(
  burglary_incidents |> 
    drop_na(latitude) |> 
    drop_na(longitude),
    coords = c('longitude', 'latitude'),
    crs = st_crs(dav_cty_census_tracts)
)

burglary_incidents_mapped
Simple feature collection with 1146 features and 27 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -92.51 ymin: 34.15 xmax: -86.557 ymax: 36.34
Geodetic CRS:  NAD83

Rename column in Davidson county census tract data so that the merge goes more smoothly.


dav_cty_census_tracts <- rename(dav_cty_census_tracts, tract_name = NAME)

Merge census csv data with dav_cty_census_tracts DC shape file data.


census_tracts <- merge(dav_cty_census_tracts, census, by.x = "TRACTCE", by.y = "tract", all = TRUE)

census_tracts
Simple feature collection with 174 features and 17 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -87.0547 ymin: 35.96778 xmax: -86.51559 ymax: 36.4055
Geodetic CRS:  NAD83
First 10 features:
   TRACTCE STATEFP COUNTYFP       GEOID tract_name            NAMELSAD MTFCC FUNCSTAT    ALAND AWATER
1   010103      47      037 47037010103     101.03 Census Tract 101.03 G5020        S 48034082  61097
2   010104      47      037 47037010104     101.04 Census Tract 101.04 G5020        S 65057849 251504
3   010105      47      037 47037010105     101.05 Census Tract 101.05 G5020        S 28328799   1093
4   010106      47      037 47037010106     101.06 Census Tract 101.06 G5020        S 21616474   6845
5   010201      47      037 47037010201     102.01 Census Tract 102.01 G5020        S 23718545      0
6   010202      47      037 47037010202     102.02 Census Tract 102.02 G5020        S 68394934  77571
7   010301      47      037 47037010301     103.01 Census Tract 103.01 G5020        S  8527942  11775
8   010302      47      037 47037010302     103.02 Census Tract 103.02 G5020        S  4179336   6813
9   010303      47      037 47037010303     103.03 Census Tract 103.03 G5020        S  4508896 142888
10  010401      47      037 47037010401     104.01 Census Tract 104.01 G5020        S  9543414 320298
      INTPTLAT     INTPTLON                                            NAME state county population
1  +36.3444054 -086.8608396 Census Tract 101.03, Davidson County, Tennessee    47    037       2411
2  +36.2940028 -086.8777483 Census Tract 101.04, Davidson County, Tennessee    47    037       3002
3  +36.2504208 -086.8521501 Census Tract 101.05, Davidson County, Tennessee    47    037       4839
4  +36.2610013 -086.8023491 Census Tract 101.06, Davidson County, Tennessee    47    037       2948
5  +36.2882537 -086.7728157 Census Tract 102.01, Davidson County, Tennessee    47    037       4283
6  +36.3619781 -086.7746355 Census Tract 102.02, Davidson County, Tennessee    47    037       3919
7  +36.3161492 -086.7261435 Census Tract 103.01, Davidson County, Tennessee    47    037       3914
8  +36.3139482 -086.7125964 Census Tract 103.02, Davidson County, Tennessee    47    037       1589
9  +36.3132279 -086.7006728 Census Tract 103.03, Davidson County, Tennessee    47    037       5114
10 +36.2943965 -086.6864670 Census Tract 104.01, Davidson County, Tennessee    47    037       4734
   median_income                       geometry
1          60000 MULTIPOLYGON (((-86.91752 3...
2          84831 MULTIPOLYGON (((-86.9744 36...
3          61115 MULTIPOLYGON (((-86.89144 3...
4          66940 MULTIPOLYGON (((-86.83089 3...
5          69185 MULTIPOLYGON (((-86.81736 3...
6          81695 MULTIPOLYGON (((-86.82483 3...
7          52806 MULTIPOLYGON (((-86.74132 3...
8          50341 MULTIPOLYGON (((-86.72469 3...
9          46604 MULTIPOLYGON (((-86.71971 3...
10         47025 MULTIPOLYGON (((-86.71149 3...
# burglary_incidents_mapped

census_tracts |> 
  ggplot() +
  geom_sf()


burglary_incidents_mapped_filtered <- st_filter(burglary_incidents_mapped, census_tracts)


census_tracts |> 
   ggplot() +
   geom_sf() +
   geom_sf(data = burglary_incidents_mapped_filtered, size = 0.1)

NA
NA
NA
NA

After performing the spatial join, merge in the census data. Note: Make sure that the final dataset contains all census tracts, even those with zero burglaries.


burglary_census_combo <- st_join(burglary_incidents_mapped, census_tracts, join = st_within, left=FALSE)

burglary_census_combo
Simple feature collection with 1142 features and 44 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -87.02 ymin: 35.99 xmax: -86.557 ymax: 36.34
Geodetic CRS:  NAD83

Part 2: Exploratory Analysis

Perform some exploratory analysis on your prepared dataset.

Classes of the two datasets:


class(census_tracts)
[1] "sf"         "data.frame"
class(burglary_census_combo)
[1] "sf"         "tbl_df"     "tbl"        "data.frame"

Curious as to the highest number of victims in one burglary.


burglary_census_combo |>
  filter(victim_number == max(victim_number, na.rm = TRUE))
Simple feature collection with 1 feature and 44 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -86.69 ymin: 36.15 xmax: -86.69 ymax: 36.15
Geodetic CRS:  NAD83

Limit dataset to non repeated incident numbers and locate the highest number of victims per indcident number.


real_num_burglaries <- burglary_census_combo |>
  group_by(incident_number) |>
  filter(victim_number == max(victim_number, na.rm = TRUE)) |>
  arrange(desc(victim_number))

real_num_burglaries
Simple feature collection with 894 features and 44 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -87.02 ymin: 35.99 xmax: -86.557 ymax: 36.34
Geodetic CRS:  NAD83

Calculate the accurate number of burglaries in each tract.


burglaries_per_tract_real <- real_num_burglaries |> 
  st_drop_geometry() |> 
  group_by(TRACTCE) |> 
  count(name = "num_burglaries") |> 
  arrange(desc(num_burglaries))

burglaries_per_tract_real
NA

Comparing the non filtered number to the result before filtering:


burglaries_per_tract <- burglary_census_combo |> 
  st_drop_geometry() |> 
  group_by(TRACTCE) |> 
  count(name = "num_burglaries") |> 
  arrange(desc(num_burglaries))

burglaries_per_tract
NA

Aggregate the data by census tract. Warning: each incident can appear multiple times if there are multiple victims, so be sure that you aren’t double-counting any incidents.


burglaries_per_tract_real
NA

Which census tract had the highest number of burglaries?


# zip = 37207
# 
# zipcodes |> 
#   filter(zipcode == zip) |> 
#   ggplot() +
#   geom_sf() +
#   geom_sf(data = bus_zips |> filter(zipcode == zip),
#           aes(color = `Route Name`))

tract = 016000

real_num_burglaries |> 
  filter(TRACTCE == tract) |> 
  ggplot() +
  geom_sf(aes(color = `incident_number`)) +
  geom_sf(data = census_tracts |> filter(TRACTCE == tract))

NA
NA

Which census tract had the highest number of burglaries per 1000 residents?

We’re interested in the relationship between median income and number of aggravated burglaries, so examine those variables on their own and together to see what you can find. You may want to perform additional calculations, create plots, etc.

LS0tDQp0aXRsZTogImNnZF9leHBsb3JhdGlvbl9nZW9zcGF0aWFsX1IiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KYGBge3J9DQoNCiMgaW5zdGFsbC5wYWNrYWdlcygic2YiKQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobGVhZmxldCkNCg0KYGBgDQoNCiMgQW5hbHl6aW5nIEFnZ3JhdmF0ZWQgQnVyZ2xhcmllcyBpbiBEYXZpZHNvbiBDb3VudHkNCiMjIyBQYXJ0IDE6IERhdGEgUHJlcGFyYXRpb24NCg0KSSBoYXZlIGJlZW4gcHJvdmlkZWQgdGhlc2UgdGhyZWUgZGF0YXNldHMgZm9yIHRoaXMgcHJvamVjdDoNCg0KMS4gYnVyZ2xhcmllc18yMDIzLmNzdjogQ29udGFpbnMgZGF0YSBvbiB0aGUgYWdncmF2YXRlZCBidXJnbGFyeSBpbmNpZGVudHMgaW4gRGF2aWRzb24gQ291bnR5LiBUaGlzIHdhcyBvYnRhaW5lZCBmcm9tIGh0dHBzOi8vZGF0YS5uYXNodmlsbGUuZ292L1BvbGljZS9NZXRyby1OYXNodmlsbGUtUG9saWNlLURlcGFydG1lbnQtSW5jaWRlbnRzLzJ1NnYtdWpqcy4NCmBgYHtyfQ0KIyByZWFkIHRoZSBjc3Ygb2YgYnVyZ2xhcmllcyBkYXRhIGludG8gdGhlIG5vdGVib29rDQoNCmJ1cmdsYXJ5X2luY2lkZW50cyA8LSByZWFkX2NzdignLi4vZGF0YS9idXJnbGFyaWVzXzIwMjMuY3N2JykNCg0KIyB2aWV3IHRoZSBkYXRhc2V0DQoNCmJ1cmdsYXJ5X2luY2lkZW50cw0KDQpgYGANCg0KSW52ZXN0aWdhdGUgdGhlIGV0aG5pY2l0eSBjb2x1bW4gc29tZTogDQoNCmBgYHtyfQ0KDQojIGludmVzdGlnYXRlIHRoZSBldGhuaWNpdHkgY29sdW1uIHNvbWUNCg0KdW5pcXVlKGJ1cmdsYXJ5X2luY2lkZW50c1tbInZpY3RpbV9ldGhuaWNpdHkiXV0pDQoNCmBgYA0KYGBge3J9DQoNCg0KDQpgYGANCg0KDQoyLiBjZW5zdXMuY3N2OiBDZW5zdXMgdHJhY3QgbGV2ZWwgZGF0YSBvbiBwb3B1bGF0aW9uIGFuZCBtZWRpYW4gaW5jb21lLiBUaGlzIHdhcyBvYnRhaW5lZCBmcm9tIHRoZSBVUyBDZW5zdXMgQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleS4NCg0KYGBge3J9DQoNCiMgcmVhZCB0aGUgY3N2IG9mIGNlbnN1cyBkYXRhIGludG8gdGhlIG5vdGVib29rDQoNCmNlbnN1cyA8LSByZWFkX2NzdignLi4vZGF0YS9jZW5zdXMuY3N2JykNCg0KIyB2aWV3IHRoZSBkYXRhc2V0DQoNCmNlbnN1cw0KDQpgYGANCg0KDQozLiBEQzogQSBzaGFwZWZpbGUgY29udGFpbmluZyBEYXZpZHNvbiBDb3VudHkgY2Vuc3VzIHRyYWN0cw0KDQpgYGB7cn0NCg0KIyByZWFkIGluIHRoZSBzaGFwZSBmaWxlIGRhdGEgZm9yIERhdmlkc29uIGNvdW50eSBjZW5zdXMgdHJhY3RzDQojIHJlYWQgaW4gdGhlIERDIGZpbGUgZGF0YQ0KDQpkYXZfY3R5X2NlbnN1c190cmFjdHMgPC0gcmVhZF9zZignLi4vZGF0YS9EQy9EQy5zaHAnKQ0KZGF2X2N0eV9jZW5zdXNfdHJhY3RzDQoNCmJ1cmdsYXJ5X2luY2lkZW50cw0KYGBgDQpgYGB7cn0NCmRhdl9jdHlfY2Vuc3VzX3RyYWN0cyB8PiANCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKCkNCmBgYA0KYGBge3J9DQpkYXZfY3R5X2NlbnN1c190cmFjdHMgfD4gDQogIGdncGxvdCgpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IEFMQU5EKSkNCmBgYA0KDQoNCg0KUGVyZm9ybSBhIHNwYXRpYWwgam9pbiB0byBkZXRlcm1pbmUgdGhlIGNlbnN1cyB0cmFjdCBpbiB3aGljaCBlYWNoIGJ1cmdsYXJ5IG9jY3VycmVkLiBIaW50OiBZb3UgbWF5IHdhbnQgdG8gbWFrZSB1c2Ugb2YgdGhlIHN0X2FzX3NmIGZ1bmN0aW9uIGluIG9yZGVyIHRvIGNvbnZlcnQgdGhlIGJ1cmdsYXJpZXMgZGF0YSBpbnRvIGFuIHNmIG9iamVjdC4NCg0KYGBge3J9DQoNCiMgcGVyZm9ybWVkIHNwYXRpYWwgam9pbiANCg0KYnVyZ2xhcnlfaW5jaWRlbnRzDQoNCmJ1cmdsYXJ5X2luY2lkZW50c19tYXBwZWQgPC0gc3RfYXNfc2YoDQogIGJ1cmdsYXJ5X2luY2lkZW50cyB8PiANCiAgICBkcm9wX25hKGxhdGl0dWRlKSB8PiANCiAgICBkcm9wX25hKGxvbmdpdHVkZSksDQogICAgY29vcmRzID0gYygnbG9uZ2l0dWRlJywgJ2xhdGl0dWRlJyksDQogICAgY3JzID0gc3RfY3JzKGRhdl9jdHlfY2Vuc3VzX3RyYWN0cykNCikNCg0KYnVyZ2xhcnlfaW5jaWRlbnRzX21hcHBlZA0KDQoNCmBgYA0KDQpSZW5hbWUgY29sdW1uIGluIERhdmlkc29uIGNvdW50eSBjZW5zdXMgdHJhY3QgZGF0YSBzbyB0aGF0IHRoZSBtZXJnZSBnb2VzIG1vcmUgc21vb3RobHkuDQoNCmBgYHtyfQ0KDQpkYXZfY3R5X2NlbnN1c190cmFjdHMgPC0gcmVuYW1lKGRhdl9jdHlfY2Vuc3VzX3RyYWN0cywgdHJhY3RfbmFtZSA9IE5BTUUpDQoNCmBgYA0KDQoNCk1lcmdlIGNlbnN1cyBjc3YgZGF0YSB3aXRoIGRhdl9jdHlfY2Vuc3VzX3RyYWN0cyBEQyBzaGFwZSBmaWxlIGRhdGEuDQoNCg0KYGBge3J9DQoNCmNlbnN1c190cmFjdHMgPC0gbWVyZ2UoZGF2X2N0eV9jZW5zdXNfdHJhY3RzLCBjZW5zdXMsIGJ5LnggPSAiVFJBQ1RDRSIsIGJ5LnkgPSAidHJhY3QiLCBhbGwgPSBUUlVFKQ0KDQpjZW5zdXNfdHJhY3RzDQojIGJ1cmdsYXJ5X2luY2lkZW50c19tYXBwZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQpjZW5zdXNfdHJhY3RzIHw+IA0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoKQ0KDQpgYGANCg0KYGBge3J9DQoNCmJ1cmdsYXJ5X2luY2lkZW50c19tYXBwZWRfZmlsdGVyZWQgPC0gc3RfZmlsdGVyKGJ1cmdsYXJ5X2luY2lkZW50c19tYXBwZWQsIGNlbnN1c190cmFjdHMpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQoNCmNlbnN1c190cmFjdHMgfD4gDQogICBnZ3Bsb3QoKSArDQogICBnZW9tX3NmKCkgKw0KICAgZ2VvbV9zZihkYXRhID0gYnVyZ2xhcnlfaW5jaWRlbnRzX21hcHBlZF9maWx0ZXJlZCwgc2l6ZSA9IDAuMSkNCg0KDQoNCg0KYGBgDQoNCg0KQWZ0ZXIgcGVyZm9ybWluZyB0aGUgc3BhdGlhbCBqb2luLCBtZXJnZSBpbiB0aGUgY2Vuc3VzIGRhdGEuIE5vdGU6IE1ha2Ugc3VyZSB0aGF0IHRoZSBmaW5hbCBkYXRhc2V0IGNvbnRhaW5zIGFsbCBjZW5zdXMgdHJhY3RzLCBldmVuIHRob3NlIHdpdGggemVybyBidXJnbGFyaWVzLg0KDQpgYGB7cn0NCg0KYnVyZ2xhcnlfY2Vuc3VzX2NvbWJvIDwtIHN0X2pvaW4oYnVyZ2xhcnlfaW5jaWRlbnRzX21hcHBlZCwgY2Vuc3VzX3RyYWN0cywgam9pbiA9IHN0X3dpdGhpbiwgbGVmdD1GQUxTRSkNCg0KDQpgYGANCg0KDQpgYGB7cn0NCg0KYnVyZ2xhcnlfY2Vuc3VzX2NvbWJvDQoNCmBgYA0KDQoNCiMjIyBQYXJ0IDI6IEV4cGxvcmF0b3J5IEFuYWx5c2lzDQoNClBlcmZvcm0gc29tZSBleHBsb3JhdG9yeSBhbmFseXNpcyBvbiB5b3VyIHByZXBhcmVkIGRhdGFzZXQuDQoNCkNsYXNzZXMgb2YgdGhlIHR3byBkYXRhc2V0czoNCg0KYGBge3J9DQoNCmNsYXNzKGNlbnN1c190cmFjdHMpDQpjbGFzcyhidXJnbGFyeV9jZW5zdXNfY29tYm8pDQoNCmBgYA0KDQpDdXJpb3VzIGFzIHRvIHRoZSBoaWdoZXN0IG51bWJlciBvZiB2aWN0aW1zIGluIG9uZSBidXJnbGFyeS4NCg0KYGBge3J9DQoNCmJ1cmdsYXJ5X2NlbnN1c19jb21ibyB8Pg0KICBmaWx0ZXIodmljdGltX251bWJlciA9PSBtYXgodmljdGltX251bWJlciwgbmEucm0gPSBUUlVFKSkNCg0KYGBgDQpMaW1pdCBkYXRhc2V0IHRvIG5vbiByZXBlYXRlZCBpbmNpZGVudCBudW1iZXJzIGFuZCBsb2NhdGUgdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIHZpY3RpbXMgcGVyIGluZGNpZGVudCBudW1iZXIuIA0KDQpgYGB7cn0NCg0KcmVhbF9udW1fYnVyZ2xhcmllcyA8LSBidXJnbGFyeV9jZW5zdXNfY29tYm8gfD4NCiAgZ3JvdXBfYnkoaW5jaWRlbnRfbnVtYmVyKSB8Pg0KICBmaWx0ZXIodmljdGltX251bWJlciA9PSBtYXgodmljdGltX251bWJlciwgbmEucm0gPSBUUlVFKSkgfD4NCiAgYXJyYW5nZShkZXNjKHZpY3RpbV9udW1iZXIpKQ0KDQpyZWFsX251bV9idXJnbGFyaWVzDQoNCmBgYA0KQ2FsY3VsYXRlIHRoZSBhY2N1cmF0ZSBudW1iZXIgb2YgYnVyZ2xhcmllcyBpbiBlYWNoIHRyYWN0Lg0KDQoNCmBgYHtyfQ0KDQpidXJnbGFyaWVzX3Blcl90cmFjdF9yZWFsIDwtIHJlYWxfbnVtX2J1cmdsYXJpZXMgfD4gDQogIHN0X2Ryb3BfZ2VvbWV0cnkoKSB8PiANCiAgZ3JvdXBfYnkoVFJBQ1RDRSkgfD4gDQogIGNvdW50KG5hbWUgPSAibnVtX2J1cmdsYXJpZXMiKSB8PiANCiAgYXJyYW5nZShkZXNjKG51bV9idXJnbGFyaWVzKSkNCg0KYnVyZ2xhcmllc19wZXJfdHJhY3RfcmVhbA0KDQpgYGANCkNvbXBhcmluZyB0aGUgbm9uIGZpbHRlcmVkIG51bWJlciB0byB0aGUgcmVzdWx0IGJlZm9yZSBmaWx0ZXJpbmc6DQoNCg0KYGBge3J9DQoNCmJ1cmdsYXJpZXNfcGVyX3RyYWN0IDwtIGJ1cmdsYXJ5X2NlbnN1c19jb21ibyB8PiANCiAgc3RfZHJvcF9nZW9tZXRyeSgpIHw+IA0KICBncm91cF9ieShUUkFDVENFKSB8PiANCiAgY291bnQobmFtZSA9ICJudW1fYnVyZ2xhcmllcyIpIHw+IA0KICBhcnJhbmdlKGRlc2MobnVtX2J1cmdsYXJpZXMpKQ0KDQpidXJnbGFyaWVzX3Blcl90cmFjdA0KDQpgYGANCg0KQWdncmVnYXRlIHRoZSBkYXRhIGJ5IGNlbnN1cyB0cmFjdC4gV2FybmluZzogZWFjaCBpbmNpZGVudCBjYW4gYXBwZWFyIG11bHRpcGxlIHRpbWVzIGlmIHRoZXJlIGFyZSBtdWx0aXBsZSB2aWN0aW1zLCBzbyBiZSBzdXJlIHRoYXQgeW91IGFyZW4ndCBkb3VibGUtY291bnRpbmcgYW55IGluY2lkZW50cy4NCg0KDQpgYGB7cn0NCg0KYnVyZ2xhcmllc19wZXJfdHJhY3RfcmVhbA0KDQpgYGANCg0KV2hpY2ggY2Vuc3VzIHRyYWN0IGhhZCB0aGUgaGlnaGVzdCBudW1iZXIgb2YgYnVyZ2xhcmllcz8gDQoNCg0KYGBge3J9DQoNCiMgemlwID0gMzcyMDcNCiMgDQojIHppcGNvZGVzIHw+IA0KIyAgIGZpbHRlcih6aXBjb2RlID09IHppcCkgfD4gDQojICAgZ2dwbG90KCkgKw0KIyAgIGdlb21fc2YoKSArDQojICAgZ2VvbV9zZihkYXRhID0gYnVzX3ppcHMgfD4gZmlsdGVyKHppcGNvZGUgPT0gemlwKSwNCiMgICAgICAgICAgIGFlcyhjb2xvciA9IGBSb3V0ZSBOYW1lYCkpDQoNCnRyYWN0ID0gMDE2MDAwIA0KIyANCiMgemlwY29kZXMgfD4gDQojICAgZmlsdGVyKHppcGNvZGUgPT0gemlwKSB8PiANCiMgICBnZ3Bsb3QoKSArDQojICAgZ2VvbV9zZigpICsNCiMgICBnZW9tX3NmKGRhdGEgPSBidXNfemlwcyB8PiBmaWx0ZXIoemlwY29kZSA9PSB6aXApLA0KIyAgICAgICAgICAgYWVzKGNvbG9yID0gYFJvdXRlIE5hbWVgKSkNCnJlYWxfbnVtX2J1cmdsYXJpZXMgfD4gDQogIGZpbHRlcihUUkFDVENFID09IHRyYWN0KSB8PiANCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKGFlcyhjb2xvciA9IGBpbmNpZGVudF9udW1iZXJgKSkgKw0KICBnZW9tX3NmKGRhdGEgPSBjZW5zdXNfdHJhY3RzIHw+IGZpbHRlcihUUkFDVENFID09IHRyYWN0KSkNCg0KDQpgYGANCg0KV2hpY2ggY2Vuc3VzIHRyYWN0IGhhZCB0aGUgaGlnaGVzdCBudW1iZXIgb2YgYnVyZ2xhcmllcyBwZXIgMTAwMCByZXNpZGVudHM/DQoNCldlJ3JlIGludGVyZXN0ZWQgaW4gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG1lZGlhbiBpbmNvbWUgYW5kIG51bWJlciBvZiBhZ2dyYXZhdGVkIGJ1cmdsYXJpZXMsIHNvIGV4YW1pbmUgdGhvc2UgdmFyaWFibGVzIG9uIHRoZWlyIG93biBhbmQgdG9nZXRoZXIgdG8gc2VlIHdoYXQgeW91IGNhbiBmaW5kLiBZb3UgbWF5IHdhbnQgdG8gcGVyZm9ybSBhZGRpdGlvbmFsIGNhbGN1bGF0aW9ucywgY3JlYXRlIHBsb3RzLCBldGMuDQoNCmBgYHtyfQ0KDQpgYGANCg0KYGBge3J9DQoNCmBgYA0KDQpgYGB7cn0NCg0KYGBgDQoNCmBgYHtyfQ0KDQpgYGANCg0KYGBge3J9DQoNCmBgYA0KDQpgYGB7cn0NCg0KYGBgDQoNCmBgYHtyfQ0KDQpgYGANCg0KYGBge3J9DQoNCmBgYA0KDQpgYGB7cn0NCg0KYGBgDQoNCg0K